package com.ktgj.common.log.aspect;

import com.alibaba.fastjson.JSON;
import com.ktgj.common.core.constant.Constants;
import com.ktgj.common.core.utils.SecurityUtils;
import com.ktgj.common.core.utils.ServletUtils;
import com.ktgj.common.core.utils.StringUtils;
import com.ktgj.common.core.utils.helper.StringHelper;
import com.ktgj.common.core.utils.ip.IpUtils;
import com.ktgj.common.log.annotation.Log;
import com.ktgj.common.log.annotation.NoRepeatSubmit;
import com.ktgj.common.log.annotation.SignatureValidation;
import com.ktgj.common.log.annotation.TokenPermission;
import com.ktgj.common.log.domain.Employee;
import com.ktgj.common.log.domain.EmployeePosition;
import com.ktgj.common.log.domain.SysMenuLoginDTO;
import com.ktgj.common.log.enums.BusinessStatus;
import com.ktgj.common.log.service.AsyncLogService;
import com.ktgj.common.redis.service.RedisService;
import com.ktgj.system.api.domain.SysOperLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 操作日志记录处理
 *
 * @author ruoyi
 */
@Aspect
@Component
public class PermissionAspect {
    private static final Logger log = LoggerFactory.getLogger(PermissionAspect.class);

    @Autowired
    private RedisService redisService;

    // 配置织入点
    @Pointcut("@annotation(com.ktgj.common.log.annotation.TokenPermission)")
    public void getPermission() {
    }


    @Before("getPermission()")
    public void doBasicProfiling(final JoinPoint joinPoint) {
        TokenPermission tokenPermissionAnnotation = getAnnotationTokenPermission(joinPoint);
        if (tokenPermissionAnnotation == null) {
            return;
        }
        HttpServletRequest request = ServletUtils.getRequest();
        String token = request.getHeader("token");// 从 http 请求头中取出 token
        if (!StringUtils.isNotEmpty(token))
        {
            return;
        }
        String routesPath = request.getHeader("routesPath");
        if (StringHelper.isNullOrEmpty(routesPath))
        {
            return;
        }

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Integer permission = getPermissionNum(token,routesPath);
        if (permission == null) {
            log.error("json无效，请重新登录");
            writeContent("json无效，请重新登录");
        }

        if (method.isAnnotationPresent(TokenPermission.class)) {
            TokenPermission tokenPermission = method.getAnnotation(TokenPermission.class);
            if (tokenPermission.value().equals("query")) {
                if (!(permission == 1 || permission == 3 || permission == 5 || permission == 9 || permission == 17 || permission == 7 || permission == 11 || permission == 19 || permission == 13 || permission == 21 || permission == 25 || permission == 15 || permission == 23 || permission == 29 || permission == 31)) {
                    log.error("您没有权限进行浏览");
                    writeContent("您没有权限进行浏览");
                }
            } else if (tokenPermission.value().equals("upd")) {
                if (!(permission == 2 || permission == 3 || permission == 6 || permission == 10 || permission == 18 || permission == 7 || permission == 11 || permission == 19 || permission == 14 || permission == 22 || permission == 26 || permission == 15 || permission == 23 || permission == 30 || permission == 31)) {
                    log.error("您没有权限进行编辑");
                    writeContent("您没有权限进行编辑");
                }
            } else if (tokenPermission.value().equals("del")) {
                if (!(permission == 4 || permission == 5 || permission == 6 || permission == 12 || permission == 20 || permission == 7 || permission == 13 || permission == 21 || permission == 14 || permission == 22 || permission == 28 || permission == 15 || permission == 23 || permission == 29 || permission == 30 || permission == 31)) {
                    log.error("您没有权限进行删除");
                    writeContent("您没有权限进行删除");
                }
            } else if (tokenPermission.value().equals("add")) {
                if (!(permission == 8 || permission == 9 || permission == 10 || permission == 12 || permission == 24 || permission == 11 || permission == 13 || permission == 25 || permission == 14 || permission == 26 || permission == 28 || permission == 15 || permission == 29 || permission == 30 || permission == 31)) {
                    log.error("您没有权限进行提交");
                    writeContent("您没有权限进行提交");
                }
            } else if (tokenPermission.value().equals("check")) {
                if (!(permission == 16 || permission == 17 || permission == 18 || permission == 20 || permission == 24 || permission == 19 || permission == 21 || permission == 25 || permission == 22 || permission == 26 || permission == 28 || permission == 23 || permission == 29 || permission == 30 || permission == 31)) {
                    log.error("您没有权限进行审核");
                    writeContent("您没有权限进行审核");
                }
            }
        }
    }

    /**
     * 根据token和路由路径来获取权限值
     * @param token 员工的token
     * @param routesPath
     * @return
     */
    public Integer getPermissionNum(String token, String routesPath)
    {
        String json = tokenUtil(token);
        Employee employee = JSON.parseObject(json, Employee.class);
        if (employee != null)
        {
            List<Long> lstPermission = new ArrayList<>();
            for (EmployeePosition employeePosition : employee.getEmployeePositions())
            {
                for (SysMenuLoginDTO menu : employeePosition.getLstMenu())
                {
                    if (menu.getMenuUrl().equals(routesPath))
                    {
                        lstPermission.add(menu.getPermission());
                    }
                }
            }
            //如果有多个角色多个权限中包含所有权限则按所有权限走
            if (lstPermission.size() > 1)
            {
                Long allPermission = lstPermission.stream().filter(item -> item.equals(31)).findFirst().orElse(null);
                if (allPermission != null)
                {
                    return allPermission.intValue();
                }
            }
            return Integer.valueOf(lstPermission.get(0).intValue());
        }
        return 31;
    }

    /**
     * 员工端登录token前缀
     */
    public final static String EMPLOYEE_LOGIN_TOKEN_KEY = "employee_login_tokens:";

    private String tokenUtil(String token) {
        // 执行认证
        if (token == null) {
            return null;
        }
        Object object = redisService.getCacheObject(EMPLOYEE_LOGIN_TOKEN_KEY + token);
        String objectMap = object != null ? object.toString() : null;

        if (objectMap == null) {
            return null;
        }

        //每操作一次，从新往redis中存一次刷新时间
        redisService.setCacheObject(EMPLOYEE_LOGIN_TOKEN_KEY + token, objectMap, Constants.TOKEN_EXPIRE * 60, TimeUnit.SECONDS);

        return objectMap;
    }

    private TokenPermission getAnnotationTokenPermission(JoinPoint joinPoint)
    {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null)
        {
            return method.getAnnotation(TokenPermission.class);
        }
        return null;
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "getPermission()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {

    }


    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "getPermission()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {

    }


    private void writeContent(String content) {
        HttpServletResponse response = ServletUtils.getResponse();
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "text/plain;charset=UTF-8");
        response.setHeader("icop-content-type", "exception");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.print(content);
        writer.flush();
        writer.close();
        response.reset();
    }

}
